Implementing Collision Detection

To implement simple collision detection to prevent the viewer from walking through walls or bookcases a modified Keyboard behavior was used. The KeyCollisionBehavior class is derived from KeyBehavior, written by Gary Moss and Andrew Cain, included with permission in the com.tornadolabs.dselman.j3d.book package.

The KeyCollisionBehavior takes a reference to a CollisionDetector interface in its constructor. If the CollisionDetector.isCollision method returns true the modified Transform3D is not applied to the TransformGroup and not movement will occur.

From KeyCollisionBehavior.java:

The KeyCollisionBehavior class adds simple collision detection to a Keyboard behavior

public class KeyCollisionBehavior extends KeyBehavior

{

private CollisionChecker m_CollisionChecker = null;

public KeyCollisionBehavior( TransformGroup tg, CollisionDetector collisionDetector )

{

super( tg );

m_CollisionChecker = new CollisionChecker( tg, collisionDetector, true );

}

before the TransformGroup is updated we need to ensure we are not going to walk into anything solidà

protected void updateTransform()

{

if( m_CollisionChecker.isCollision( transform3D ) == false )

transformGroup.setTransform(transform3D);

}

dissallow rotation up or down

protected void altMove(int keycode)

{

}

dissallow moving up or down

protected void controlMove(int keycode)

{

}

}

The main application Applet class implements the CollsionDetector interface with its single method, isCollision, as follows. The first method does a quick check to ensure we are still within the boundaries of our world, if this passes, then the second method is used to check which pixel in the map image corresponds to our 3D world coordinate position (only the X and Z coordinate are used).

From KeyNavigateTest.java:

return true if the Transform3D would put us into collision with a "solid" object in the world

public boolean isCollision( Transform3D t3d, boolean bViewSide )

{

get the translation from the Transform3D

t3d.get( m_Translation );

we need to scale up by the scale that was applied to the root TG on the view side of the scenegraph

if( bViewSide != false )

m_Translation.scale( 1.0 / getScale() );

Vector3d mapSquareSize = getMapSquareSize();

first check that we are still inside the "world" û we canÆt walk outside it

if( m_Translation.x < -FLOOR_WIDTH + mapSquareSize.x ||

m_Translation.x > FLOOR_WIDTH - mapSquareSize.x ||

m_Translation.y < -FLOOR_LENGTH + mapSquareSize.y ||

m_Translation.y > FLOOR_LENGTH - mapSquareSize.y )

return true;

then do a pixel based look up using the map

if( bViewSide != false )

return isCollision( m_Translation );

return false;

}

If the very fast check that we are still inside the world passes then we need to lookup the pixel in the map image that our new position will fall within. Once we have queried the color of that pixel we will know if we can enter that location.

returns true if the given x,z location in the world corresponds to a wall section

protected boolean isCollision( Vector3d worldCoord )

{

Point2d point = convertToMapCoordinate( worldCoord );

int nImageWidth = m_MapImage.getWidth();

int nImageHeight = m_MapImage.getHeight();

outside of image

if( point.x < 0 || point.x >= nImageWidth ||

point.y < 0 || point.y >= nImageHeight )

return true;

Color color = new Color( m_MapImage.getRGB( (int) point.x, (int) point.y ) );

we can't walk through walls or bookcases

return( color.hashCode() == m_ColorWall.hashCode() ||

color.hashCode() == m_ColorBookcase.hashCode() );

}

This very simple grid-based collision detection algorithm works fairly well for this application as it exploits knowledge of the scene, as well as constraint on the userÆs movement. Incidentally, the "Guard" objects that move around the scene also hook into the same CollsionDetection interface implemented by the application object. For these objects however, bViewSize == true and they are allowed to penetrate through walls and bookcases to catch the unwary by surprise!

Another neat feature of the example is the use of transparent bitmaps for both water and flaming torches. The flaming torches also use a computationally inexpensive and simple form of texture animation and are discussed in the next section.